package cc.rengu.redp.bizimpl.utils;

import cc.rengu.igas.bomp.facade.base.Header;
import cc.rengu.redp.bizimpl.bean.FieldInfo;
import cc.rengu.redp.bizimpl.bean.LabelValueBean;
import cc.rengu.redp.bizimpl.constant.UpmpConstant;
import cc.rengu.redp.bizimpl.enums.BompQueryTypeEnum;
import cc.rengu.redp.bizimpl.enums.DBCharsetEnum;
import cc.rengu.redp.bizimpl.enums.IgasYesOrNoEnum;
import cc.rengu.redp.bizimpl.enums.OrgLevelEnum;
import cc.rengu.redp.bizimpl.upmp.common.BusinessContainer;
import cc.rengu.redp.bizimpl.upmp.domain.UpmpOrganization;
import cc.rengu.redp.bizimpl.upmp.domain.UpmpSysParam;
import cc.rengu.redp.bizimpl.upmp.service.IUpmpSysParamService;
import cc.rengu.redp.bizimpl.upmp.vo.ExcelColumnAttr;
import cc.rengu.redp.bizimpl.upmp.vo.UpmpUserInfoVO;
import cc.rengu.redp.common.exception.RedpException;
import cc.rengu.redp.common.utils.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * 公共工具类
 */
public class CommonUtils {

    private final static Logger logger = LoggerFactory.getLogger(CommonUtils.class);

    /* 默认银行代码 */
    public final static String defaultTxnAreaId = "00";

    /* 记录状态 */
    public final static String ineffective = "0";

    /* 记录状态 */
    public final static String effective = "1";


    private static char[] numbers = ("0123456789").toCharArray();

    public static enum Direction {
        right, left
    }

    /**
     * 账户标识
     */
    public static enum AccountFlag {
        /**
         * 账户标识-内部户
         */
        inner,
        /**
         * 账户标识-账户号、卡号
         */
        cardNo
    }

    /**
     * 报文objname
     */
    public static enum AccountFlagObj {
        /**
         * 报文objname-账户号、卡号
         */
        CHECK_STATUS,
        /**
         * 报文objname-内部户
         */
        CHECK_STATUS_INNER
    }

    /**
     * 将字符串以补字符或者去掉字符的方式转换成指定长度字符串， 如果传入字符串参数的长度超过传入的长度参数，则将根据方位去掉数字多余位数
     *
     * @param orgnum 需要转换的数字
     * @param supStr 补充的字符
     * @param length 长度
     * @return
     */
    public static String getSpecLengthNum(String orgnum, char supStr, Direction direct, int length) {
        if (orgnum.length() > length) {
            if (direct.equals(Direction.right)) {
                return orgnum.substring(orgnum.length() - length);
            } else {
                return orgnum.substring(0, orgnum.length() - length);
            }
        } else if (orgnum.length() == length) {
            return orgnum;
        } else {
            char[] orgnumChar = new char[length - orgnum.length()];
            for (int i = 0; i < length - orgnum.length(); i++) {
                orgnumChar[i] = supStr;
            }
            if (direct.equals(Direction.left)) {
                return String.valueOf(orgnumChar) + orgnum;
            } else {
                return orgnum + String.valueOf(orgnumChar);
            }
        }
    }

    /**
     * 字符串转数字
     *
     * @param str
     * @return
     */
    public static boolean changeStr(String str) {
        try {
            Integer.valueOf(str);
            // Integer in = Integer.valueOf(str);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 十进制转换中把字符转换为数字，区分大小写，A-10，a-35
     *
     * @param input
     * @param base
     */
    public static BigInteger toDecimal(String input, int base) {
        BigInteger Bigtemp = BigInteger.ZERO, temp = BigInteger.ONE;
        int len = input.length();
        for (int i = len - 1; i >= 0; i--) {
            if (i != len - 1) {
                temp = temp.multiply(BigInteger.valueOf(base));
            }
            int num = changeDec(input.charAt(i));
            Bigtemp = Bigtemp.add(temp.multiply(BigInteger.valueOf(num)));
        }
        // System.out.println(Bigtemp);
        return Bigtemp;
    }

    /**
     * 区分大小写，A-10，a-35
     *
     * @param ch
     * @return
     */
    public static int changeDec(char ch) {
        int num = 0;
        if ('A' <= ch && ch <= 'Z') {
            num = ch - 'A' + 10;
        } else if ('a' <= ch && ch <= 'z') {
            num = ch - 'a' + 36;
        } else {
            num = ch - '0';
        }
        return num;
    }

    /**
     * 发送socket报文，并返回请求结果
     *
     * @param ip      服务端IP
     * @param port    服务端端口
     * @param jsonStr 请求报文(JSon格式字符串)
     * @return
     */
    public static String sendSocket(String ip, int port, String jsonStr) {
        Socket socket = null;
        String ret = new String();
        DataOutputStream outputStream = null;
        DataInputStream instr = null;
        try {
            logger.info("Socket请求开始，ip：[{}]，端口：[{}]", ip, port);
            System.out.println("Socket请求开始，ip：" + ip + "，端口：" + port);
            // 创建一个流套接字并将其连接到指定主机上的指定端口号
            socket = new Socket();
            socket.connect(new InetSocketAddress(ip, port), 1000);//设置连接请求超时时间10 s
            socket.setSoTimeout(30000);//设置读操作超时时间30s
            logger.info("Socket连接建立，ip：[{}]，端口：[{}]，链接超时时间:[{}],读操作超时时间:[{}]", ip, port, 1000, 30000);
//    		BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            // 向服务器端发送数据
            byte[] jsonByte = jsonStr.getBytes("UTF-8");
            String sendLen = String.format("%04d", jsonByte.length);
            int sendLenByte = sendLen.getBytes().length;
            System.out.println("<send len> = [" + sendLen + "] <byte len> = [" + sendLenByte + "]");

            byte[] sendByte = new byte[sendLenByte + jsonByte.length];
            // System.arraycopy(sendByte, 0, sendLen.getBytes(), 0, sendLenByte);
            System.arraycopy(sendLen.getBytes(), 0, sendByte, 0, sendLenByte);
            System.arraycopy(jsonByte, 0, sendByte, sendLenByte, jsonByte.length);
            // String inStr = String.format("%04d", jsonStr.length()) + jsonStr;// 长度值不包括前面4位长度值的长度
            // logger.info("请求报文[" + inStr + "]");
            // byte[] jsonByte = inStr.getBytes("UTF-8"); // 将String转化为byte[]

            // byte[] sendLenByte = String.valueOf(sendLen).getBytes();
            // byte[] sendByte = new byte[jsonByte.length + sendLenByte.length];

            outputStream = new DataOutputStream(socket.getOutputStream());
            logger.info("请求报文长度：" + jsonByte.length);

            // System.out.println(jsonByte.length);
            // System.out.println(jsonByte);
            // System.out.println(new String (jsonByte));
            // outputStream.write(jsonByte);
            outputStream.write(sendByte);
            outputStream.flush();
            logger.info("传输数据完毕");
            socket.shutdownOutput();
            instr = new DataInputStream(socket.getInputStream());
            byte[] len = new byte[4];
            instr.read(len, 0, 4);// 前4位为报文长度值，read之后会自动从instr中去除
            String slen = new String(len);
            logger.info("socket对象读取前4个字节数据为[" + slen + "]");
            int totallen = (int) Integer.valueOf(slen).intValue();
            if (totallen < 0 || totallen > 9999) {// 报文长度为4位数字，最大值9999
                logger.error("返回报文长度[" + totallen + "]错误");
                throw new IOException("报文长度[" + totallen + "]错误");
            }
//          return read(instr, totallen);
            byte[] msg = new byte[totallen];
            instr.read(msg, 0, totallen);
            ret = new String(msg, "UTF-8");
            logger.info("服务器端返回信息为：[" + ret + "]");
//			outputStream.close();
//			instr.close();
        } catch (Exception e) {
            e.printStackTrace();
            ip = e.getMessage();
            logger.error("客户端异常:" + e.getMessage());
            System.out.println(e.getMessage());
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    socket = null;
                    logger.error("客户端 finally 异常:" + e.getMessage());
                }
            }
            if (null != outputStream) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    outputStream = null;
                    logger.error("SOCKET客户端输出流关闭异常:" + e.getMessage(), e);
                }
            }
            if (null != outputStream) {
                try {
                    instr.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    instr = null;
                    logger.error("SOCKET客户端数据输入流关闭异常:" + e.getMessage(), e);
                }
            }
        }
        return ret;
    }


    public static int findRealRows(Sheet sheet) {

        int num = 0;
        if (sheet.getLastRowNum() > 0) {

            for (; num < sheet.getLastRowNum(); num++) {
                Row row = sheet.getRow(num);
                String cell = getValue(row.getCell((short) 0));

                if ("".equals(cell)) {
                    break;
                }
            }
        }
        return num;
    }
/*
    public static int findRealRows(XSSFSheet sheet){

        int num = 0;
        if( sheet.getLastRowNum() > 0 ){

            for( ; num < sheet.getLastRowNum(); num ++){
                Row row = sheet.getRow(num);
                String cell = getValue(row.getCell((short)0));

                if( "".equals(cell) ){
                    break;
                }
            }
        }
        return num;
    }*/

    public static String getValue(Cell cell) {
        if (cell == null) {
            return "";
        } else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            DecimalFormat df = new DecimalFormat("0");
            String format = df.format(cell.getNumericCellValue());
            return format;
        } else {
            return String.valueOf(cell.getStringCellValue());
        }
    }

    /**
     * 此方法实现
     * 返回的Map集合对数据的自动
     * 封装功能
     * List集合存储着一系列的MAP
     * 对象，obj为一个javaBean
     *
     * @param list Map集合
     * @param obj  javaBean对象
     * @return
     */
    public static <T> List<T> parseListmapToBean(List list, Class<T> obj) {
        //生成集合
        ArrayList ary = new ArrayList();
        //遍历集合中的所有数据
        for (int i = 0; i < list.size(); i++) {
            try {
                ////生成对象实历 将MAP中的所有参数封装到对象中
                T o = (T) addProperty((Map) list.get(i), obj.newInstance());
                //把对象加入到集合中
                ary.add(o);
            } catch (InstantiationException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //返回封装好的集合
        return ary;
    }


    /**
     * 此方法实现返回的Map集合对数据的自动封装功能
     * obj为一个javaBean
     *
     * @param map 集合
     * @param obj javaBean对象
     * @return
     */
    public static <T> T parseMapToBean(Map map, Class<T> obj) {

        try {
            ////生成对象实历 将MAP中的所有参数封装到对象中
            T o = (T) addProperty(map, obj.newInstance());

            return o;
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //返回封装好的集合
        return null;
    }

    /**
     * Map对象中的值为 name=aaa,value=bbb
     * 调用方法
     * addProperty(map,user);
     * 将自动将map中的值赋给user类
     *
     * @param map 存储着名称和值集合
     * @param obj 要封装的对象
     * @return封装好的对象
     */
    private static Object addProperty(Map map, Object obj) {
        //遍历所有名称
        Iterator it = map.keySet().iterator();
        while (it.hasNext()) {
            //取得名称
            String name = it.next().toString();
            //取得值
            String value = map.get(name) == null ? "" : map.get(name).toString();
            try {
                //取得值的类型
                Class type = PropertyUtils.getPropertyType(obj, name);
                if (type != null) {
                    //设置参数
                    PropertyUtils.setProperty(obj, name, ConvertUtils.convert(value, type));
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return obj;
    }

    /**
     * 给对象指定字段赋值
     *
     * @param name  字段名
     * @param value 字段值
     * @param obj   对象实例
     * @return
     */
    public static Object addProperty(String name, String value, Object obj) {
        try {
            //取得值的类型
            Class type = PropertyUtils.getPropertyType(obj, name);
            if (type != null) {
                //设置参数
                PropertyUtils.setProperty(obj, name, ConvertUtils.convert(value, type));
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return obj;
    }

    public static boolean isBaseDefaultValue(Object object) {
        if (object instanceof Integer) {
            return true;
        } else if (object instanceof Byte) {
            return true;
        } else if (object instanceof Long) {
            return true;
        } else if (object instanceof Double) {
            return true;
        } else if (object instanceof Float) {
            return true;
        } else if (object instanceof Character) {
            return true;
        } else if (object instanceof Short) {
            return true;
        } else if (object instanceof Boolean) {
            return true;
        } else if (object instanceof String) {
            return true;
        }
        return false;
    }

    /**
     * 根据数据库字符集类型判断字符串长度
     *
     * @param value
     * @param charset
     * @return
     */
    public static int strDBLength(String value, DBCharsetEnum charset) {
        int valueLength = 0;
        String chinese = "[\u0391-\uFFE5]";
        /* 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1 */
        for (int i = 0; i < value.length(); i++) {
            /* 获取一个字符 */
            String temp = value.substring(i, i + 1);
            /* 判断是否为中文字符 */
            if (temp.matches(chinese)) {
                /* 中文字符长度根据数据库字符集取值 */
                valueLength += charset.getChineseLen();
            } else {
                /* 其他字符长度为1 */
                valueLength += 1;
            }
        }
        return valueLength;
    }


    /**
     * 根据数据库字符集类型判断字符串长度
     *
     * @param value
     * @return
     */
    public static int strDBLength(String value) throws Exception {
        String dbCharset = CommonUtils.getProperties("ValidationMessages.properties", "encoding");
        if (StringUtils.isEmpty(dbCharset)) {
            logger.error("解析文件时获取系统参数[MCHNT_DB_CHARSET]值失败，请联系系统管理员");
            throw new Exception("解析文件时获取系统参数[MCHNT_DB_CHARSET]值失败，请联系系统管理员");
        }
        DBCharsetEnum charset;
        if (DBCharsetEnum.SIMPLIFIED_CHINESE_CHINA_AL32UTF8.getType().equals(dbCharset)) {
            charset = DBCharsetEnum.SIMPLIFIED_CHINESE_CHINA_AL32UTF8;
        } else {
            charset = DBCharsetEnum.SIMPLIFIED_CHINESE_CHINA_ZHS16GBK;
        }

        int valueLength = 0;
        String chinese = "[\u0391-\uFFE5]";
        /* 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1 */
        for (int i = 0; i < value.length(); i++) {
            /* 获取一个字符 */
            String temp = value.substring(i, i + 1);
            /* 判断是否为中文字符 */
            if (temp.matches(chinese)) {
                /* 中文字符长度根据数据库字符集取值 */
                valueLength += charset.getChineseLen();
            } else {
                /* 其他字符长度为1 */
                valueLength += 1;
            }
        }
        return valueLength;
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    public static String getProperties(String fileName, String key) throws Exception {
        InputStream readStream = getReadStream(fileName);
        if (null == readStream) {
            throw new Exception("获取配置文件失败");
        }
        Properties prop = new Properties();
        prop.load(readStream);
        return prop.getProperty(key);
    }

    public static boolean isFileFolderExist(String name) {
        boolean result = false;
        if (!StringUtils.isEmpty(name)) {
            File file = new File(name);
            result = file.exists();
        }
        return result;
    }

    public static InputStream getReadStream(String fileName) {
        URL url = CommonUtils.class.getResource("/" + fileName);
        String realFileName = "";
        boolean canReadAsFile = false;
        InputStream inputStream;
        if (null != url) {
            realFileName = url.getFile();
            if (CommonUtils.isFileFolderExist(realFileName)) {
                canReadAsFile = true;
            }
        }
        if (canReadAsFile) {
            try {
                inputStream = new FileInputStream(realFileName);
            } catch (FileNotFoundException e) {
                logger.error(e.getMessage());
                inputStream = null;
            }
        } else {
            inputStream = CommonUtils.class.getResourceAsStream("/" + fileName);
        }

        return inputStream;
    }


    public static String getSubString(String value, int beginIndex) {
        return getSubString(value, beginIndex, -999);
    }

    /**
     * 以字节来进行字符串截取
     * 如果是UTF-8字符集：一个汉字=3个字节
     * String cde = "字符串截取cde";
     * String c = this.getSubString(cde,0,3);
     * System.out.println(c); // 得到“字”
     * String c = this.getSubString(cde,0,9);
     * System.out.println(c); // 得到“字符串”
     * String c = this.getSubString(cde,0,16);
     * System.out.println(c); // 得到“字符串截取c”
     *
     * @param value      需要截取的字符串
     * @param beginIndex 截取的开始下标位置
     * @param endIndex   截取结束的下标位置
     * @return 处理后字符串
     */
    public static String getSubString(String value, int beginIndex, int endIndex) {
        String dbCharset;
        try {
            dbCharset = CommonUtils.getProperties("application.properties", "MCHNT_DB_CHARSET");
        } catch (Exception e) {
            logger.error("解析文件时获取系统参数[MCHNT_DB_CHARSET]值失败，请联系系统管理员");
            throw new StringIndexOutOfBoundsException("解析文件时获取系统参数[MCHNT_DB_CHARSET]值失败，请联系系统管理员");
        }
        if (StringUtils.isEmpty(dbCharset)) {
            logger.error("解析文件时获取系统参数[MCHNT_DB_CHARSET]值失败，请联系系统管理员");
            throw new StringIndexOutOfBoundsException("解析文件时获取系统参数[MCHNT_DB_CHARSET]值失败，请联系系统管理员");
        }
        DBCharsetEnum charset;
        if (DBCharsetEnum.SIMPLIFIED_CHINESE_CHINA_AL32UTF8.getType().equals(dbCharset)) {
            charset = DBCharsetEnum.SIMPLIFIED_CHINESE_CHINA_AL32UTF8;
        } else {
            charset = DBCharsetEnum.SIMPLIFIED_CHINESE_CHINA_ZHS16GBK;
        }

        byte[] strToBytes;
        try {
            strToBytes = value.getBytes(charset.getType());
        } catch (UnsupportedEncodingException e) {
            throw new StringIndexOutOfBoundsException("获取字符串byte数组失败");
        }

        if (endIndex == -999) {
            endIndex = strToBytes.length;
        }
        if (((beginIndex == 0) && (endIndex == strToBytes.length)) || org.apache.commons.lang3.StringUtils.isBlank(value)) {
            return value;
        }
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > strToBytes.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }

        // Note: offset or count might be near -1>>>1.
        if (beginIndex > strToBytes.length - subLen) {
            throw new StringIndexOutOfBoundsException(beginIndex + subLen);
        }

        StringBuilder sb = new StringBuilder();
        int count = 0;
        char[] c = value.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] > 256) {
                count += 3;
            } else {
                count++;
            }
            if (count > beginIndex && count <= endIndex) {
                sb.append(c[i]);
            }
        }
        return sb.toString();
    }

    /**
     * 根据机构信息同时转换成 对象对应机构等级的机构号
     * @param org
     * @param object
     * @throws RedpException
     */
    public static void setOrgCodeToObject(UpmpOrganization org,Object object) throws RedpException {
        if (!ObjectUtils.isEmpty(object)) {
            Field field=null;
            try {
                if (org.getOrgLevel().equals(OrgLevelEnum.BUSINESS_DEPARTMENT.getType())) {
                    field = object.getClass().getDeclaredField("fourOrgCode");
                } else if (org.getOrgLevel().equals(OrgLevelEnum.SUB_BRANCH.getType())) {
                    field = object.getClass().getDeclaredField("threeOrgCode");
                } else if (org.getOrgLevel().equals(OrgLevelEnum.BRANCH.getType())) {
                    field = object.getClass().getDeclaredField("secondOrgCode");
                } else if (org.getOrgLevel().equals(OrgLevelEnum.HEAD.getType())) {
                    field = object.getClass().getDeclaredField("firstOrgCode");
                }
                if (!ObjectUtils.isEmpty(field)) {
                    //设置对象的访问权限，保证对private的属性的访问
                    field.setAccessible(true);
                    field.set(null, org.getOrgCode());
                }
            }catch (Exception ex){
                throw new RedpException(ex.getMessage());
            }
        }
    }

    /**
     * 获得某个对象的类所声明的字段的字段名、字段中文名、字段、字段值、是否库表字段，
     * 这种字段即包括public、private和proteced，但是不包括父类的申明字段
     *
     * @param fieldName
     * @param object
     * @return
     * @throws RedpException
     */
    public static FieldInfo getFieldValueByFieldName(String fieldName, Object object) throws RedpException {

        if (ObjectUtils.isEmpty(object)) {
            return null;
        }
        FieldInfo info = new FieldInfo();
        info.setFieldName(fieldName);
        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            //设置对象的访问权限，保证对private的属性的访问
            field.setAccessible(true);
            TableField trans = field.getAnnotation(TableField.class);
            if (!trans.exist()) {//判断是否库表字段
                info.setTransiantFlag(IgasYesOrNoEnum.No.getType());
            } else {
                info.setTransiantFlag(IgasYesOrNoEnum.Yes.getType());
            }

            Object value = field.get(object);

            String valueStr = "";
            if (null == value) {

            } else if (field.getType().getClass().equals(java.util.Date.class)) {
                valueStr = DateUtil.getDateFormat((Date) value, "yyyy-MM-dd HH:mm:ss");
            } else if (value.getClass().isPrimitive()) {
                valueStr = null == value ? "" : String.valueOf(value);
            } else if (isBaseDefaultValue(value)) {
                valueStr = null == value ? "" : String.valueOf(value);
            } else if (value instanceof List || value instanceof Map || value instanceof Set) {
                valueStr = JSON.toJSONString(value);
            } else if (value instanceof Serializable) {
                valueStr = JSON.toJSONString(value);
            }
            info.setValue(valueStr);

            return info;
        } catch (Exception e) {
            throw new RedpException(e.getMessage());
        }
    }

    /**
     * 比较数据修改前后的差异
     *
     * @param tmpData    修改后
     * @param formalData 修改前
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<LabelValueBean> compareData(T tmpData, T formalData, Class<T> clazz) throws RedpException {
        List<LabelValueBean> compareBeans = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        if (Common.isNotBlank(fields)) {
            for (Field field : fields) {
                FieldInfo tmpField = CommonUtils.getFieldValueByFieldName(field.getName(), tmpData);
                FieldInfo formalField = CommonUtils.getFieldValueByFieldName(field.getName(), formalData);
                if (null != tmpField && null == formalField) {
                    LabelValueBean bean = new LabelValueBean();
                    if (field.getAnnotation(ApiModel.class) != null) {
                        bean.setLabel(field.getAnnotation(ApiModel.class).value());
                    }
                    bean.setElabel(field.getName());
                    bean.setValue("");
                    compareBeans.add(bean);
                } else if ((null == tmpField && null != formalField) || ((null != tmpField && null != formalField)
                        && (!tmpField.getValue().equals(formalField.getValue())))) {
                    LabelValueBean bean = new LabelValueBean();
                    String value = formalField.getValue();
                    if (null != field.getAnnotation(ApiModel.class)) {
                        bean.setLabel(field.getAnnotation(ApiModel.class).value());
                    }
                    bean.setElabel(field.getName());
                    bean.setValue(value);
                    compareBeans.add(bean);
                }
            }
        }
        return compareBeans;
    }

    /**
     * 从数据字典表取序列号的渠道id
     *
     * @param sysParamService
     * @return
     */
    public static String getChannelId(IUpmpSysParamService sysParamService, String instid) {
        String channelId = "";
        List<UpmpSysParam> queryList = sysParamService.findChildrenByPrimaryKey(BusinessContainer.dataDict_ChannelId_KEY, instid, null);
        if (null != queryList && queryList.size() > 0) {
            UpmpSysParam sysParam = queryList.get(0);
            if (!Common.isBlank(sysParam.getPrimaryValue())) {
                channelId = sysParam.getPrimaryValue();
            }
        }
        // 如果查询结果为空，赋默认值
        if ("".equals(channelId)) {
            channelId = BusinessContainer.dataDict_ChannelId_DFT;
        }
        return channelId;
    }

    public static UpmpUserInfoVO getCurrentUser(IUpmpSysParamService upmpSysParamService) {
        // 获取当前登录用户信息
        UpmpSysParam defaultInst = upmpSysParamService.getById(UpmpConstant.DEAFULT_INST_PARAM_ID);
        UpmpUserInfoVO user = RedpUpmpUtil.getCurrentUser(defaultInst.getInstId());
        return user;
    }

    /**
     * 组装 mcmp 到 bomp 报文头
     *
     * @param traceNo
     * @param txnNum
     * @param instId
     * @return
     */
    public static Header packageBompHeader(String traceNo, String txnNum, String instId,String bizType) {
        Header header = new Header();
        header.setVersion(BusinessContainer.BOMP_VERSION);
        header.setTraceNo(traceNo);
        header.setTxnNum(txnNum);
        header.setTransDate(getCurrentDate("yyyyMMdd"));
        header.setTransTime(getCurrentDate("HHmmss"));
        if(StringUtils.isEmpty(bizType)){
            header.setBizType(BusinessContainer.IGAS_DEFAULT_BIZ_TYPE);
        }else{
            header.setBizType(bizType);
        }
        header.setChanlId(BusinessContainer.UPMP_CHANL_ID);
        header.setSrcSysId(BusinessContainer.MCMP_SRC_SYS_ID);
        header.setInstId(instId);
        return header;
    }

    /**
     * 组装 mcmp 到 momp 报文头
     *
     * @param traceNo
     * @param txnNum
     * @param instId
     * @return
     */
    public static Header packageMompHeader(String traceNo, String txnNum, String instId, String bizType) {
        Header header = new Header();
        header.setVersion(BusinessContainer.MOMP_VERSION);
        header.setTraceNo(traceNo);
        header.setTxnNum(txnNum);
        header.setTransDate(getCurrentDate("yyyyMMdd"));
        header.setTransTime(getCurrentDate("HHmmss"));
        if(org.springframework.util.StringUtils.isEmpty(bizType)){
            header.setBizType(BompQueryTypeEnum.REAL.getType());
        }else{
            header.setBizType(bizType);
        }
        header.setChanlId(BusinessContainer.MCMP_CHANL_ID);
        header.setSrcSysId(BusinessContainer.MOMP_SRC_SYS_ID);
        header.setInstId(instId);
        return header;
    }

    /**
     * 根据日期格式获取对应当前日期
     *
     * @param format 日期格式
     * @return
     */
    public static synchronized String getCurrentDate(String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date());
    }

    /**
     * 校验当前用户与法人行是否匹配
     *
     * @param instId
     * @throws RedpException
     */
    public static void validateUserInst(String instId, UpmpUserInfoVO user) throws RedpException {
        if (!user.isAdmin()) {
            if (!instId.equals(user.getInstId())) {
                logger.error("不支持的操作，法人行[{}]与用户所属法人行[{}]不匹配。", instId, user.getInstId());
                throw new RedpException("不支持的操作，法人行[" + instId + "]与用户所属法人行[" + user.getInstId() + "]不匹配。");
            }
        }
    }

    /*生成UUID*/
    public static String getUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }
    /**
     * 从数据字典表里面取某一类枚举值
     * @param primaryKey      枚举值的标识
     * @return
     */
    public static Map<String, Object> dataDictToSelect2(IUpmpSysParamService upmpSysParamService, String primaryKey,String instId) {
        // Map<String, String> map = new HashMap<String, String>();
        List<UpmpSysParam> queryList = upmpSysParamService.findChildrenByPrimaryKey(primaryKey,instId,null);

        List<Object> list = new ArrayList<Object>();
        Map<String, Object> map = new HashMap<String, Object>();
        for (UpmpSysParam param : queryList) {
            if (!param.getPrimaryKey().equals("03")) {
                Map<String, String> maps = new HashMap<String, String>();
                maps.put("id", param.getPrimaryKey());
                maps.put("name", param.getPrimaryValue());
                list.add(maps);
            }
        }
        map.put("results", list);
        map.put("more", false);
        return map;
    }
    public static String getSequenceNext(String seqName, JdbcTemplate jdbcTemplate) {
        try {
            String sql = "select " + seqName + ".Nextval as next from dual";
            Map<String, Object> map = jdbcTemplate.queryForMap(sql);
            return null == map || null == map.get("next") ? "" : map.get("next").toString();
        } catch (Exception e) {
            logger.error("交易出现异常，异常信息：" + e.getMessage());
        }
        return null;
    }
    /* 产生随机数值字符串  */
    public static String randomNumStr(int length) {
        Random numGen = new Random();
        if (length < 1) {
            length = 32;
        }
        char[] randBuffer = new char[length];
        for (int i = 0; i < randBuffer.length; i++) {
            randBuffer[i] = numbers[numGen.nextInt(9)];
        }
        return new String(randBuffer);
    }

    /**
     * 校验excel单元格输入值
     *
     * @param cellVal
     * @param colAttr
     * @param rowNum
     * @param dbCharsetEnum
     * @param sheetName
     * @return
     */
    public static StringBuffer validatSheetCellValue(String cellVal, ExcelColumnAttr colAttr, int rowNum
            , DBCharsetEnum dbCharsetEnum, String sheetName) {
        StringBuffer errBuff = new StringBuffer();
        int realRowNum = rowNum + 1;
        if (Common.isBlank(cellVal)) {//判断是否必填
            if (colAttr.isRequiredFlag()) {
                logger.error("导入文件中{}sheet页第{}行{}列值不能为空！", sheetName, realRowNum, colAttr.getColumnName());
                errBuff.append("导入文件中" + sheetName + "sheet页第" + realRowNum + "行" + colAttr.getColumnName() + "列值不能为空！");
                errBuff.append("\\r\\n");
                return errBuff;
            }
        } else {
            if (cellVal.indexOf("-") >= 0) {
                cellVal = cellVal.substring(0, cellVal.indexOf("-"));
            }
            if (cellVal.indexOf("_") >= 0) {
                cellVal = cellVal.substring(0, cellVal.indexOf("_"));
            }
            int length = strDBLength(cellVal, dbCharsetEnum);
            if (length > colAttr.getMaxLength()) {//判断是否超长
                logger.error("导入文件中{}sheet页第{}行{}列值长度超过{}(单个汉字长度为{})！", sheetName, realRowNum, colAttr.getColumnName(), colAttr.getMaxLength(), dbCharsetEnum.getChineseLen());
                errBuff.append("导入文件中" + sheetName + "sheet页第" + realRowNum + "行" + colAttr.getColumnName() + "列值长度超过{" + colAttr.getMaxLength() + "}(单个汉字长度为{" + dbCharsetEnum.getChineseLen() + "})！");
                errBuff.append("\\r\\n");
                return errBuff;
            }
            if (Common.isNotBlank(colAttr.getValidatMethodEnum())) {
                String regValidRst = StringValicationUtil.validate(colAttr.getValidatMethodEnum(), cellVal);
                if (Common.isNotBlank(regValidRst)) {
                    logger.error("导入文件中{}sheet页第{}行{}列值 {}！", sheetName, realRowNum, colAttr.getColumnName(), regValidRst);
                    errBuff.append("导入文件中" + sheetName + "sheet页第" + realRowNum + "行" + colAttr.getColumnName() + "列值 " + regValidRst);
                    errBuff.append("\\r\\n");
                    return errBuff;
                }
            }
        }
        return errBuff;
    }
}
